package org.swxjava.servlet;

import java.lang.reflect.InvocationTargetException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.swxjava.Call;
import org.swxjava.CallHandler;
import org.swxjava.ErrorMessage;
import org.swxjava.Marshaller;
import org.swxjava.Remoter;
import org.swxjava.Reply;
import org.swxjava.core.DefaultRemoter;
import org.swxjava.core.SwxRpcMarshaller;
import org.swxjava.util.Log;
import org.swxjava.util.LogFactory;

public class DefaultCallHandler implements CallHandler {

	private static final Log LOG = LogFactory.getLog(DefaultCallHandler.class);

	private Remoter remoter;
	private Marshaller marshaller;

	public DefaultCallHandler() {
		setMarshaller(new SwxRpcMarshaller());
		setRemoter(new DefaultRemoter());
	}

	public void handle(HttpServletRequest request, HttpServletResponse response) {
		try {
			// parse args
			Call call = marshaller.marshallInbound(request, response);
			
			try {
				Reply reply = remoter.execute(call);
				marshaller.marshallOutbound(reply, request, response);
			} catch (InvocationTargetException e) {
				// Handle the exception thrown in while executing the method.
				handleError(request, response, call, e.getTargetException());
			} catch (Throwable th) {
				handleError(request, response, call, th);
			}
			
		} catch (Throwable th) {
			handleError(request, response, null, th);
		}
	}
	
	protected void handleError(HttpServletRequest request, HttpServletResponse response, Call call, Throwable th) {
		th.printStackTrace();
		try {
			ErrorMessage errorMessage = new ErrorMessage();
			errorMessage.setJavaClassName(th.getClass().getName());
			errorMessage.setMessage(th.getMessage());
			Reply reply = null;
			if(call != null) {
				reply = new Reply(call.getCallId(), errorMessage, call.getUrl(), call.isDebug());
			} else {
				reply = new Reply(null, errorMessage, null, true);
			}
			marshaller.marshallOutbound(reply, request, response);
		} catch (Exception e) {
			e.printStackTrace();
			LOG.error(e);
		}
	}

	public Remoter getRemoter() {
		return remoter;
	}

	public void setRemoter(Remoter remoter) {
		this.remoter = remoter;
	}

	public Marshaller getMarshaller() {
		return marshaller;
	}

	public void setMarshaller(Marshaller marshaller) {
		this.marshaller = marshaller;
	}
}